﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.IO;


namespace APNS.NET
{
    public class ApnsStream : Stream
    {

        private readonly X509Certificate _apnCertificate;
        private readonly TcpClient _apnClient;
        private readonly SslStream _apnStream;

        // Create connection
        public ApnsStream(string hostname, int port, X509Certificate apnCertificate)
        {
            if (apnCertificate==null)
                throw new ArgumentNullException("apnCertificate");

            this._apnCertificate = apnCertificate;
      
            _apnClient = new TcpClient(hostname, port);
            _apnStream = new SslStream(
                    _apnClient.GetStream(),
                    false,
                    ValidateServerCertificate,
                    SelectLocalCertificate);

            _apnStream.AuthenticateAsClient(
                hostname,
                new X509CertificateCollection() {apnCertificate}, 
                SslProtocols.Ssl3, 
                false);
        }

        public override void Flush()
        {
            _apnStream.Flush();
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            throw new NotSupportedException();
        }

        public override void SetLength(long value)
        {
            throw new NotSupportedException();
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            return _apnStream.Read(buffer, offset, count);
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            _apnStream.Write(buffer, offset, count);
        }

        public override bool CanRead
        {
            get { return _apnClient.Connected; }
        }

        public override bool CanSeek
        {
            get { return false; }
        }

        public override bool CanWrite
        {
            get { return _apnClient.Connected; }
        }

        public override long Length
        {
            get { return _apnClient.Available; }
        }

        public override long Position
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }

        // Always trust the server certificate - TODO: should we?
        private static bool ValidateServerCertificate(
                        object sender,
                        X509Certificate certificate,
                        X509Chain chain,
                        SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }

        // Return our apns certificate
        private X509Certificate SelectLocalCertificate(
                        object sender,
                        string targetHost,
                        X509CertificateCollection localCertificates,
                        X509Certificate remoteCertificate,
                        string[] acceptableIssuers)
        {
            return _apnCertificate;
        }

        public override void Close()
        {
            _apnClient.Close();
            _apnStream.Close();
            base.Close();
        }

        protected override void Dispose(bool disposing)
        {
            if(disposing)
            {
                _apnStream.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}
